package at.chl.genetic.random;

import java.util.ArrayList;
import java.util.List;

import at.chl.genetic.node.IDecisionNode;
import at.chl.genetic.node.builder.INodeBuilder;

public abstract class AbstractRandomDecisionNodeFactory implements IRandomDecisionNodeFactory{

	private List<INodeBuilder> registeredNodeBuilders;
	private long maxDepth=IRandomDecisionNodeFactory.DEFAULT_MAX_DEPTH;
	private long maxChilds=IRandomDecisionNodeFactory.DEFAULT_MAX_CHILDS;
	
	public void setMaxChilds(long maxChilds) {
		this.maxChilds = maxChilds;
	}

	private long depthCount;
	private long childCount;
	
	public AbstractRandomDecisionNodeFactory(){
		this(new ArrayList<INodeBuilder>());
	}
	
	public AbstractRandomDecisionNodeFactory(List<INodeBuilder> registeredNodeBuilders){
		this.registeredNodeBuilders=registeredNodeBuilders;
	}
	
	@Override
	public boolean registerDecisionNodeBuilder(INodeBuilder nodeBuilder) {
		return registeredNodeBuilders.add(nodeBuilder);
		
	}

	@Override
	public void setMaxDepth(long maxDepth) {
		this.maxDepth=maxDepth;
	}

	public IDecisionNode createDecisionTree(Long startDepth,Long startChilds){
		
		depthCount=startDepth;
		childCount=startChilds;
		IDecisionNode root=createRandomFullNode();
		depthCount=0;
		childCount=0;
		return root;
	}
	
	@Override
	public IDecisionNode createDecisionTree() {
		
		depthCount=0;
		childCount=0;
		IDecisionNode root=createRandomFullNode();
		depthCount=0;
		childCount=0;
		return root;
	}

	

	public List<INodeBuilder> getRegisteredNodeBuilders() {
		return registeredNodeBuilders;
	}

	public void setRegisteredNodeBuilders(List<INodeBuilder> registeredNodeBuilders) {
		this.registeredNodeBuilders = registeredNodeBuilders;
	}

	private IDecisionNode createRandomFullNode() {
		//childs can get a bit more then max if the last allowed node 
		//needs more childs then the dif between childCount and maxChilds
		depthCount++;
		childCount++;
		
		IDecisionNode node=createRandomNode((depthCount<=maxDepth)&&(childCount<=maxChilds));
		
		long childCount=node.getChildrenCount();
		
		List<IDecisionNode> childs=new ArrayList<IDecisionNode>();
		
		if(childCount>0){
			
			for(long i=0;i<childCount;i++){
				//recursive call!!
				childs.add(createRandomFullNode());
			}
		}
		
		depthCount--;
		
		node.setChildNodes(childs);
		
		
		return node;
	}

	abstract public IDecisionNode createRandomNode(boolean allowChilds) ;

	
	
	
}
